<?php

namespace fastphp;

// 添加对所有需要的类的引用
use fastphp\Router;
use fastphp\Db;
use fastphp\Request;
use fastphp\Response;
use fastphp\Facade;
use fastphp\util\Log;
use fastphp\Session;
use fastphp\MiddlewareManager;

/**
 * FastPHP核心类
 * 负责初始化框架环境、处理请求分发和管理服务容器
 */
class Core
{
    /**
     * 服务容器
     * @var array
     */
    protected $container = [];

    /**
     * 运行应用程序
     */
    public function run()
    {
        // 注册自动加载器
        spl_autoload_register(array($this, 'loadClass'));

        // 初始化环境设置
        $this->setReporting();
        $this->unregisterGlobals();
        
        // 注册错误和异常处理器
        $this->registerErrorHandlers();

        // 初始化服务容器
        $this->initContainer();

        // 处理请求
        $this->dispatchRequest();
    }

    /**
     * 初始化服务容器
     */
    // 在initContainer方法中注册Session服务
    // 在initContainer方法中添加Config服务的注册
    private function initContainer()
    {
        // 注册核心服务到容器
        $this->container['router'] = new Router();
        
        // 先初始化配置服务，因为数据库连接池需要配置
        $this->container['config'] = new \fastphp\Config();
        
        // 初始化数据库服务，使用连接池
        $this->container['db'] = new Db();
        
        // 其他服务注册
        $this->container['request'] = new Request();
        $this->container['response'] = new Response();
        $this->container['validator'] = new Validator();
        $sessionConfig = isset($GLOBALS['config']['session']) ? $GLOBALS['config']['session'] : [];
        $this->container['session'] = new Session($sessionConfig);
        
        // 添加中间件管理器
        $this->container['middleware'] = new MiddlewareManager($this);
        
        // 设置容器到 Facade 基类
        Facade::setContainer($this);
    }
    
    /**
     * 从容器获取服务
     * @param string $key 服务键名
     * @return mixed 服务实例
     */
    public function get($key)
    {
        return $this->container[$key] ?? null;
    }

    /**
     * 向容器注册服务
     * @param string $key 服务键名
     * @param mixed $value 服务实例或闭包
     */
    public function set($key, $value)
    {
        $this->container[$key] = $value;
    }

    /**
     * 分发请求到路由系统
     */
    protected function loadConfigs()
    {
        // 缓存键名
        $cacheKey = 'app_configs';
        $cacheFile = RUNTIME_PATH . 'cache/config.cache.php';
        
        // 检查是否有缓存且调试模式关闭
        if (file_exists($cacheFile) && !defined('APP_DEBUG')) {
            // 加载缓存的配置
            $cachedConfig = include $cacheFile;
            $config = $this->get('config');
            
            foreach ($cachedConfig as $prefix => $items) {
                foreach ($items as $key => $value) {
                    $config->set($prefix . '.' . $key, $value);
                }
            }
            return;
        }
        
        // 正常加载配置文件
        $configDir = CONFIG_PATH;
        $config = $this->get('config');
        $files = glob($configDir . '*.php');
        
        // 收集所有配置以便缓存
        $allConfigs = [];
        
        foreach ($files as $file) {
            if (basename($file) !== 'config.php' && basename($file) !== 'middleware.php') {
                $prefix = basename($file, '.php');
                $fileConfig = include $file;
                $config->load($file, $prefix);
                
                // 收集配置用于缓存
                $allConfigs[$prefix] = $fileConfig;
            }
        }
        
        // 如果不是调试模式，缓存配置
        if (!defined('APP_DEBUG')) {
            file_put_contents($cacheFile, '<?php return ' . var_export($allConfigs, true) . ';');
        }
    }
    
    // 修改dispatchRequest方法，在加载路由前加载配置文件
    protected function dispatchRequest()
    {
        try {
            // 获取请求URI
            $requestUri = $this->getRequestUri();
            
            // 加载所有配置文件
            $this->loadConfigs();
            
            // 加载路由配置
            $this->loadRoutes();
            
            // 加载中间件配置
            $this->loadMiddleware();
            
            // 使用容器中的router实例，而不是静态调用
            $this->get('router')->dispatch($requestUri);
        } catch (\Throwable $e) {
            // 使用Throwable捕获所有异常和错误（PHP 7+）
            $this->handleException($e);
        }
    }
    
    // 添加加载中间件配置的方法
    // 修改loadMiddleware方法，正确加载并注册中间件配置
    protected function loadMiddleware()
    {
        $middlewareFile = APP_PATH . '/config/middleware.php';
        if (file_exists($middlewareFile)) {
            // 使用include获取配置文件的返回值
            $middlewareConfig = include $middlewareFile;
            
            // 获取中间件管理器实例
            $middlewareManager = $this->get('middleware');
            
            // 注册中间件别名
            if (isset($middlewareConfig['alias']) && is_array($middlewareConfig['alias'])) {
                foreach ($middlewareConfig['alias'] as $name => $class) {
                    $middlewareManager->alias($name, $class);
                }
            }
            
            // 注册全局中间件
            if (isset($middlewareConfig['global']) && is_array($middlewareConfig['global'])) {
                $middlewareManager->addGlobal($middlewareConfig['global']);
            }
        }
    }

    /**
     * 获取请求URI
     * @return string 请求的URI路径
     */
    protected function getRequestUri()
    {
        // 获取当前请求的 URI
        $requestUri = $_SERVER['REQUEST_URI'] ?? '/';
    
        // 去除查询字符串
        if (strpos($requestUri, '?') !== false) {
            $requestUri = explode('?', $requestUri)[0];
        }
    
        // 处理index.php的情况
        $indexPhpPos = strpos($requestUri, 'index.php/');
        if ($indexPhpPos !== false) {
            $pathAfterIndexPhp = substr($requestUri, $indexPhpPos + strlen('index.php'));
            if ($pathAfterIndexPhp && $pathAfterIndexPhp[0] !== '/') {
                $pathAfterIndexPhp = '/' . $pathAfterIndexPhp;
            }
            return $pathAfterIndexPhp;
        }
    
        // 确保路径以/开头
        if ($requestUri && $requestUri[0] !== '/') {
            $requestUri = '/' . $requestUri;
        }
    
        return $requestUri;
    }

    /**
     * 加载路由配置文件
     */
    protected function loadRoutes()
    {
        // 获取路由目录路径
        $routeDir = APP_PATH . '/route';
        
        // 确保路径格式正确，特别是在Windows环境下
        $routeDir = str_replace('/', DIRECTORY_SEPARATOR, $routeDir);
        
        // 检查路由目录是否存在
        if (is_dir($routeDir)) {
            // 使用glob获取目录下所有PHP文件
            $routeFiles = glob($routeDir . DIRECTORY_SEPARATOR . '*.php');
            
            // 确保获取到了文件
            if (!empty($routeFiles)) {
                // 循环加载每个路由文件
                foreach ($routeFiles as $routeFile) {
                    if (file_exists($routeFile)) {
                        require_once $routeFile;
                    }
                }
            } else {
                // 如果开启了调试模式，可以输出提示信息
                if (defined('APP_DEBUG') && APP_DEBUG) {
                    echo "警告: 路由目录存在但未找到任何PHP文件<br>";
                }
            }
        } else {
            // 如果开启了调试模式，可以输出提示信息
            if (defined('APP_DEBUG') && APP_DEBUG) {
                echo "警告: 路由目录不存在: " . $routeDir . "<br>";
            }
        }
    }

    /**
     * 检测开发环境并设置错误报告级别
     */
    protected function setReporting()
    {
        if (APP_DEBUG) {
            error_reporting(E_ALL);
            ini_set('display_errors', 'On');
        } else {
            error_reporting(E_ALL);
            ini_set('display_errors', 'Off');
            ini_set('log_errors', 'On');

            // 确保日志目录存在
            $errorLogDir = RUNTIME_PATH . 'log/error/';
            if (!is_dir($errorLogDir)) {
                mkdir($errorLogDir, 0755, true);
            }

            // 设置错误日志文件
            $errorLogFile = $errorLogDir . date('Ymd') . '.log';
            ini_set('error_log', $errorLogFile);
        }
    }

    /**
     * 检测自定义全局变量（register globals）并移除
     * 注：此功能在PHP 5.4.0后已被移除，但保留以兼容旧版本
     */
    protected function unregisterGlobals()
    {
        if (ini_get('register_globals')) {
            $array = array('_SESSION', '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
            foreach ($array as $value) {
                foreach ($GLOBALS[$value] as $key => $var) {
                    if ($var === $GLOBALS[$key]) {
                        unset($GLOBALS[$key]);
                    }
                }
            }
        }
    }

    /**
     * 自动加载控制器和模型类
     * @param string $class 类名
     */
    // 修改loadClass方法，使用更高效的自动加载策略
    public function loadClass($class)
    {
        // 将命名空间分隔符替换为目录分隔符
        $classPath = str_replace('\\', '/', $class);
        
        // 优化类文件路径查找逻辑
        if (strpos($class, 'application\\') === 0) {
            // 应用类（控制器、模型等）
            $file = APP_PATH . str_replace('application/', 'application/', $classPath) . NORMAL_EXT;
        } else {
            // 框架核心类
            $file = ROOT . str_replace('fastphp/', '', $classPath) . NORMAL_EXT;
        }
        
        if (file_exists($file)) {
            include $file;
        }
    }
    
    /**
     * 注册错误和异常处理器
     */
    protected function registerErrorHandlers()
    {
        // 注册自定义错误处理器
        set_error_handler([$this, 'handleError']);
        
        // 注册自定义异常处理器
        set_exception_handler([$this, 'handleException']);
        
        // 注册PHP关闭前的致命错误处理
        register_shutdown_function([$this, 'handleShutdown']);
    }
    
    /**
     * 自定义错误处理器
     * @param int $errno 错误级别
     * @param string $errstr 错误信息
     * @param string $errfile 错误文件
     * @param int $errline 错误行号
     * @return bool 是否继续标准PHP错误处理
     */
    // 优化错误处理，减少日志记录
    public function handleError($errno, $errstr, $errfile, $errline)
    {
        // 忽略被@抑制的错误
        if (error_reporting() === 0) {
            return false;
        }
        
        // 在生产环境只记录严重错误
        if (!defined('APP_DEBUG') || !APP_DEBUG) {
            // 只处理致命错误
            $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING];
            if (!in_array($errno, $fatalErrors)) {
                return true;
            }
        }
        
        // 将PHP错误转换为错误描述
        $errorType = $this->getErrorType($errno);
        
        // 构建错误消息
        $errorMessage = "{$errorType}: {$errstr} in {$errfile} on line {$errline}";
        
        // 只有在调试模式下才获取详细请求信息
        $requestInfo = defined('APP_DEBUG') && APP_DEBUG ? $this->getRequestInfo() : '';
        
        // 完整的错误日志信息
        $logMessage = "{$errorMessage}" . ($requestInfo ? "\n{$requestInfo}\n" : '');
        
        // 根据错误级别记录到不同的日志类别
        switch ($errno) {
            case E_ERROR:
            case E_PARSE:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
                Log::error($logMessage, 'error');
                break;
            default:
                // 在生产环境减少警告级别的日志
                if (defined('APP_DEBUG') && APP_DEBUG) {
                    Log::warning($logMessage, 'warning');
                }
        }
        
        // 调试模式下显示错误
        if (defined('APP_DEBUG') && APP_DEBUG) {
            echo '<div style="background: #ffeeee; border: 1px solid #ff0000; padding: 10px; margin: 10px;">';
            echo '<h2>PHP错误</h2>';
            echo '<p>' . $errorMessage . '</p>';
            echo '</div>';
        }
        
        return true;
    }
    
    /**
     * 自定义异常处理器
     * @param \Throwable $e 异常对象（Throwable可以捕获Exception和Error）
     */
    public function handleException($e)
    {
        // 构建异常消息
        $errorMessage = get_class($e) . ": {$e->getMessage()} in {$e->getFile()} on line {$e->getLine()}";
        $trace = $e->getTraceAsString();
        
        // 获取请求信息
        $requestInfo = $this->getRequestInfo();
        
        // 完整的异常日志信息
        $logMessage = "{$errorMessage}\nStack trace:\n{$trace}\n{$requestInfo}\n";
        
        // 记录异常日志
        Log::error($logMessage, 'exception');
        
        // 设置HTTP状态码
        http_response_code(500);
        
        if (APP_DEBUG) {
            // 调试模式下显示详细异常信息
            echo '<div style="background: #ffeeee; border: 1px solid #ff0000; padding: 10px; margin: 10px;">';
            echo '<h2>框架异常</h2>';
            echo '<p>' . $errorMessage . '</p>';
            echo '<pre>Stack trace:\n' . $trace . '</pre>';
            echo '</div>';
        } else {
            // 非调试模式下显示友好错误页面
            // if (defined('DEF_ERROR_PAGE') && file_exists(DEF_ERROR_PAGE)) {
            //     require_once DEF_ERROR_PAGE;
            // } else 
            if (isset($GLOBALS['config']['error']['default_page']) && file_exists($GLOBALS['config']['error']['default_page'])) {
                require_once $GLOBALS['config']['error']['default_page'];
            } else {
                echo '请求的页面不存在或发生错误';
            }
        }
    }
    
    /**
     * 处理PHP关闭前的致命错误
     */
    public function handleShutdown()
    {
        // 检查是否有致命错误
        $error = error_get_last();
        
        if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR])) {
            // 构建错误消息
            $errorType = $this->getErrorType($error['type']);
            $errorMessage = "{$errorType}: {$error['message']} in {$error['file']} on line {$error['line']}";
            
            // 获取请求信息
            $requestInfo = $this->getRequestInfo();
            
            // 完整的错误日志信息
            $logMessage = "[FATAL] {$errorMessage}\n{$requestInfo}\n";
            
            // 记录致命错误日志
            Log::error($logMessage, 'fatal');
        }
    }
    
    /**
     * 获取错误类型描述
     * @param int $errno 错误代码
     * @return string 错误类型描述
     */
    protected function getErrorType($errno)
    {
        switch ($errno) {
            case E_ERROR: return 'E_ERROR';
            case E_WARNING: return 'E_WARNING';
            case E_PARSE: return 'E_PARSE';
            case E_NOTICE: return 'E_NOTICE';
            case E_CORE_ERROR: return 'E_CORE_ERROR';
            case E_CORE_WARNING: return 'E_CORE_WARNING';
            case E_COMPILE_ERROR: return 'E_COMPILE_ERROR';
            case E_COMPILE_WARNING: return 'E_COMPILE_WARNING';
            case E_USER_ERROR: return 'E_USER_ERROR';
            case E_USER_WARNING: return 'E_USER_WARNING';
            case E_USER_NOTICE: return 'E_USER_NOTICE';
            case E_STRICT: return 'E_STRICT';
            case E_DEPRECATED: return 'E_DEPRECATED';
            case E_USER_DEPRECATED: return 'E_USER_DEPRECATED';
            default: return 'UNKNOWN_ERROR';
        }
    }
    
    /**
     * 获取当前请求信息
     * @return string 请求信息描述
     */
    protected function getRequestInfo()
    {
        $requestInfo = [];
        $requestInfo[] = "Request URI: " . ($_SERVER['REQUEST_URI'] ?? 'unknown');
        $requestInfo[] = "Request Method: " . ($_SERVER['REQUEST_METHOD'] ?? 'unknown');
        $requestInfo[] = "Client IP: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
        $requestInfo[] = "User Agent: " . ($_SERVER['HTTP_USER_AGENT'] ?? 'unknown');
        
        if (!empty($_GET)) {
            $requestInfo[] = "GET Parameters: " . json_encode($_GET);
        }
        
        if (!empty($_POST)) {
            // 避免记录敏感信息
            $safePost = $_POST;
            if (isset($safePost['password'])) $safePost['password'] = '******';
            if (isset($safePost['password_confirmation'])) $safePost['password_confirmation'] = '******';
            $requestInfo[] = "POST Parameters: " . json_encode($safePost);
        }
        
        return implode("\n", $requestInfo);
    }
}